# coding:utf-8

import bpy
import bmesh
import struct
import mathutils
import math


from bpy_extras.io_utils import (ImportHelper,
									ExportHelper,
									path_reference_mode,
									axis_conversion,
									)
		
from bpy.props import BoolProperty
from bpy.props import EnumProperty
from bpy.props import StringProperty

OT_FLUID = 30



#保存对象名称
def SaveObjName(file, name):
	#保存文本数量
	file.write( struct.pack('I', len(name)) )
	for i in range(len(name)):
		file.write( struct.pack('B', ord(name[i])) )

#保存帧
def WriteFrame(binFile, keys):
	#保存帧数量
	binFile.write( struct.pack('I', len(keys)) )
	print('len(keys) = ', len(keys))
	#保存帧编号
	for co in keys:
		binFile.write( struct.pack('i', int(co[0])) )
	#保存帧关键帧值
	for co in keys:
		binFile.write( struct.pack('f', co[1]) )
#保存帧
def WriteFrame_Rotation(binFile, keys):
	#保存帧数量
	binFile.write( struct.pack('I', len(keys)) )
	print('len(keys) = ', len(keys))
	#保存帧编号
	for co in keys:
		binFile.write( struct.pack('i', int(co[0])) )
	#保存帧关键帧值
	for co in keys:
		print('co[1] = ', co[1])
		print('degrees co[1] = ', math.degrees(co[1]))
		binFile.write( struct.pack('f', math.degrees(co[1])) )
		
	

#保存流体对象
def WriteFluidObj(binFile):
	#保存为流体域
	binFile.write( struct.pack('I', OT_FLUID) )
	
	

def Engne_ExportPolaygons(context, select, path):
	objs = []
	if select:
		objs = context.selected_objects
	else:
		for m in bpy.data.objects:
			objs.append(m)
	
	binFile = open(path, 'wb')
	#保存版本
	binFile.write( struct.pack('I', 1) )
	
	
	#迭代所有选择对象
	for obj in objs:
		#保存对象名称
		SaveObjName(binFile, obj.name)
		
		
		
		if obj.type == 'MESH':
			#查找修改器 保存其他类型
			if obj.modifiers.find('Fluidsim') >= 0:
				WriteFluidObj(binFile)
			else:
				me = obj.data
				bm = bmesh.new()
				bm.from_mesh(me)
				
				
				bmesh.ops.scale(bm, vec=mathutils.Vector((1.0, -1.0, 1.0)), space=mathutils.Matrix.Scale(1, 4, (1.0, 1.0, 1.0)), verts=bm.verts[:])
				bmesh.ops.rotate(bm, verts=bm.verts[:], cent=(1.0, 0.0, 0.0), matrix=mathutils.Matrix.Rotation(math.radians(-90.0), 3, 'X'))
				bmesh.ops.recalc_face_normals(bm, faces=bm.faces[:])
				#bmesh.ops.reverse_uvs(bm, faces=bm.faces[:]);
				#bmesh.ops.rotate_uvs(bm, faces=bm.faces[:], use_ccw=False);
				
				#数据组
				UVCoord = []
				Normal = []
				Vertex = []
				VIndex = []
				VWeight = []
				#FaIndex
				
				#bmesh.ops.recalc_face_normals(bm, faces=bm.faces[:])
				bm.faces.ensure_lookup_table()
				uv_lay = bm.loops.layers.uv.active
				for face in bm.faces:
					face.normal_flip()
					
					for loop in face.loops:
						uv = loop[uv_lay].uv
						vert = loop.vert
						UVCoord.append(struct.pack('f', uv[0]))
						UVCoord.append(struct.pack('f', uv[1]*-1))
						
						for v in vert.co:
							Vertex.append(struct.pack('f', v))
						
						for n in vert.normal:
							Normal.append(struct.pack('f', n))
						#for vert in face.verts:
						
						#权重数据
						groups = me.vertices[vert.index].groups
						if len(groups) > 0 :
							weightGroup = []
							for g in groups:
								#所在组的索引 当前顶点权重值
								groupID_weight = [g.group, g.weight]
								weightGroup.append(groupID_weight)
								
							VWeight.append(weightGroup)
						else:
							VWeight.append([])
							
						
						VIndex.append(struct.pack('I', len(VIndex)))
						
						
						
				bm.free()
				
				#保存对象类型
				binFile.write( struct.pack('I', 1) )
				
				
				#保存定点数量
				binFile.write( struct.pack('I', len(Vertex)) )
				print("顶点数量", len(Vertex))
				#保存定点
				for vertex in Vertex:
					binFile.write( vertex )
					
				#保存法线数量
				binFile.write( struct.pack('I', len(Normal)) )
				print("Normal", len(Normal))
				#保存法线
				for normal in Normal:
					binFile.write( normal )
					
				#保存纹理坐标数量
				binFile.write( struct.pack('I', len(UVCoord)) )
				print("UVCoord", len(UVCoord))
				#保存纹理坐标
				for uv in UVCoord:
					binFile.write( uv )
					
				#保存索引数量
				binFile.write( struct.pack('I', len(VIndex)) )
				print("VIndex", len(VIndex))
				#保存索引
				for index in VIndex:
					binFile.write( index )
				
				
				#保存顶点权重组数量
				binFile.write( struct.pack('B', len(obj.vertex_groups)) )
				binFile.write( struct.pack('I', len(VWeight)) )
				print("权重数量", len(VWeight))
				#保存顶点权重 --顶点索引--顶点权重--
				for indexAndWeight in VWeight :
					if len(indexAndWeight) > 0 :
						#写出权重组数量
						binFile.write(struct.pack('B', len(indexAndWeight)))
						for weightGroup in indexAndWeight :
							binFile.write( struct.pack('I', weightGroup[0]) )
							binFile.write( struct.pack('f', weightGroup[1]) )
					else:
						binFile.write( struct.pack('B', 0) )
						
				
				
				
		
		if obj.type == 'LAMP':
			binFile.write( struct.pack('I', 2) )
			
			#保存灯光类型
			if obj.data.type == 'POINT':
				binFile.write( struct.pack('I', 1) )
			elif obj.data.type == 'SUN':
				binFile.write( struct.pack('I', 2) )
			elif obj.data.type == 'SPOT':
				binFile.write( struct.pack('I', 3) )
			else:
				binFile.write( struct.pack('I', 2) )
			
			#保存灯光亮度
			binFile.write( struct.pack('f', obj.data.energy) )
			
		
		if obj.type == 'CAMERA':
			binFile.write( struct.pack('I', 3) )
			#保存摄像机视野角度 弧度值
			binFile.write( struct.pack('f', obj.data.angle) )
		
		
		#是否有动画
		
		#保存帧动画
		if obj.animation_data != None:
			#写入有动画数据
			binFile.write( struct.pack('I', 111) )
			
			locationX = []
			locationY = []
			locationZ = []
			rotationX = []
			rotationY = []
			rotationZ = []
			scaleX = []
			scaleY = []
			scaleZ = []
			
			for fcurve in obj.animation_data.action.fcurves:
				if fcurve.data_path == 'location':
					if fcurve.array_index == 0 :
						#保存动画X轴移动动画
						for framePoint in fcurve.keyframe_points:
							locationX.append(framePoint.co)
							
					if fcurve.array_index == 1 :
						#保存动画Y轴移动动画
						for framePoint in fcurve.keyframe_points:
							locationY.append(framePoint.co)
							
					if fcurve.array_index == 2 :
						#保存动画Z轴移动动画
						for framePoint in fcurve.keyframe_points:
							locationZ.append(framePoint.co)
							
				elif fcurve.data_path == 'rotation_euler':
					if fcurve.array_index == 0 :
						#保存动画X轴旋转动画
						for framePoint in fcurve.keyframe_points:
							rotationX.append(framePoint.co)
					if fcurve.array_index == 1 :
						#保存动画Y轴旋转动画
						for framePoint in fcurve.keyframe_points:
							rotationY.append(framePoint.co)
					if fcurve.array_index == 2 :
						#保存动画Z轴旋转动画
						for framePoint in fcurve.keyframe_points:
							rotationZ.append(framePoint.co)
							
						
				elif fcurve.data_path == 'scale':
					if fcurve.array_index == 0 :
						#保存动画X轴缩放动画
						for framePoint in fcurve.keyframe_points:
							scaleX.append(framePoint.co)
					if fcurve.array_index == 1 :
						#保存动画Y轴缩放动画
						for framePoint in fcurve.keyframe_points:
							scaleY.append(framePoint.co)
					if fcurve.array_index == 2 :
						#保存动画Z轴缩放动画
						for framePoint in fcurve.keyframe_points:
							scaleZ.append(framePoint.co)
					
				#obj.animation_data.action.groups['Location'].channels[0].keyframe_points[0].co[1]	
			#保存动画X轴移动动画帧数量
			print(obj.name)
			WriteFrame(binFile, locationX)
			#保存动画Z轴移动动画帧数量
			WriteFrame(binFile, locationZ)
			#保存动画Y轴移动动画帧数量
			WriteFrame(binFile, locationY)
			
			
			print(rotationX)
			#保存动画X轴旋转动画帧数量
			WriteFrame_Rotation(binFile, rotationX)
			#保存动画Z轴旋转动画帧数量
			WriteFrame_Rotation(binFile, rotationZ)
			#保存动画Y轴旋转动画帧数量
			WriteFrame_Rotation(binFile, rotationY)
			
			
			print(scaleX)
			#保存动画X轴缩放动画帧数量
			WriteFrame(binFile, scaleX)
			#保存动画Z轴缩放动画帧数量
			WriteFrame(binFile, scaleZ)
			#保存动画Y轴缩放动画帧数量
			WriteFrame(binFile, scaleY)
			
			
		else:
			binFile.write( struct.pack('I', 0) )
			
		#写入无动画数据
		#保存对象型位置
		binFile.write( struct.pack('f', obj.location[0]) )
		binFile.write( struct.pack('f', obj.location[2]) )
		binFile.write( struct.pack('f', obj.location[1]) )
		#保存对象旋转角度
		binFile.write( struct.pack('f', math.degrees(obj.rotation_euler[0])) )
		binFile.write( struct.pack('f', math.degrees(obj.rotation_euler[2])) )
		binFile.write( struct.pack('f', math.degrees(obj.rotation_euler[1])) )
		#保存对象缩放比例
		binFile.write( struct.pack('f', obj.scale[0]) )
		binFile.write( struct.pack('f', obj.scale[2]) )
		binFile.write( struct.pack('f', obj.scale[1]) )
	
	binFile.write( struct.pack('I', 60000) )
	
	binFile.close()
	
	
	
	
	
	
	

class Engine_ExportMM(bpy.types.Operator, ExportHelper):
	bl_idname = "export_scene.ms"
	bl_label = 'Export MS'
	bl_options = {'PRESET'}
	
	#filename_ext = StringProperty(subtype='FILE_PATH')
	filename_ext = '.ms'
	filepath = StringProperty(subtype='FILE_PATH')
	
	SelectOnly = BoolProperty(name="导出选定对象", description="导出选定对象", default=False)
	
	
	def execute(self, context):
		#self.filename_ext = "mbt.mm"
		#from.import export_obj
		#selectOnly = self.SelectOnly[1]['default']
		Engne_ExportPolaygons(context, self.SelectOnly, self.filepath)
		#Engine_SaveModel(context, self.SelectOnly, self.filepath)
		return {'FINISHED'}
		#return export_obj.save(self, context, **keywords)


def menu_func_export(self, context):
	self.layout.operator(Engine_ExportMM.bl_idname, text="场景文件 (.ms)")
	
	
def register():
	bpy.utils.register_module(__name__)
	bpy.types.INFO_MT_file_export.append(menu_func_export)
	
def unregister():
	bpy.utils.unregister_module(__name__)
	bpy.types.INFO_MT_file_export.remove(menu_func_export)
	
	
if __name__ == "__main__":
	register()
	
	
	